package com.example.qxfw.nyqx.service.impl;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.example.qxfw.nyqx.mapper.AgriProductMapper;
import com.example.qxfw.nyqx.service.*;
import com.example.qxfw.common.entity.ny.AgriWeatherDistRecord;
import com.example.qxfw.common.entity.ny.CropyieldFcst;
import com.example.qxfw.common.entity.ny.CropyieldHistory;
import com.example.qxfw.common.entity.ny.StationInfo;
import com.example.qxfw.common.entity.qx.MsgMediumSmallScale;
import com.example.qxfw.nyqx.dto.NyClDto;
import com.example.qxfw.nyqx.vo.CropYieldFcstListVo;
import com.example.qxfw.nyqx.vo.CropYieldHistoryListVo;
import com.example.qxfw.common.entity.zy.AgriProduct;
import com.example.qxfw.mongodb.hy.entity.HyDocFile;
import com.example.qxfw.mongodb.hy.service.DocFileService;
import com.example.qxfw.rcyw.service.StationInfoService;
import com.example.qxfw.ybzz.service.MsgMediumSmallScaleService;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.io.*;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

import static com.example.qxfw.common.util.DocxUtil.replaceTextInParagraphWithSubscript;

@Service
public class YieldForecastServiceImpl implements YieldForecastService {

    @Autowired
    private AgriProductMapper agriProductMapper;

    @Value("${filePath.docFilePath}")
    private String docFilePath;

    @Autowired
    private StationInfoService stationInfoService;

    @Autowired
    private MsgMediumSmallScaleService msgMediumSmallScaleService;

    @Autowired
    private CropyieldHistoryService cropyieldHistoryService;

    @Autowired
    private AgriWeatherDistRecordService agriWeatherDistRecordService;

    @Autowired
    private CropyieldFcstService cropyieldFcstService;

    @Autowired
    private AgriProductService agriProductService;

    @Autowired
    private DocFileService docFileService;

    @Override
    public NyClDto calculate(long year, String stationId, String type) {
        double temp = 0.0;//9月中旬的积温
        double avgTemp = 0.0;//9月中旬平均温度
        //区域自动站站点ID
        String smallScaleStationId;
        StationInfo nyStation = stationInfoService.getById(stationId);
        smallScaleStationId = nyStation.getSmallscalestationid();

        //9月中旬的积温
        int count = 0;
        for (int i = 11; i <= 20; i++) {
            String time1 = year + "-09-" + i + " 00:00:00";
            String time2 = year + "-09-" + i + " 23:00:00";

            MsgMediumSmallScale msgMediumSmallScale = msgMediumSmallScaleService.selectMaxMinTempByParam(time1, time2, smallScaleStationId);
            if (msgMediumSmallScale != null && msgMediumSmallScale.getMaxtemp() != null && msgMediumSmallScale.getMintemp() != null) {
                temp += (msgMediumSmallScale.getMaxtemp() + msgMediumSmallScale.getMintemp()) / 2;
                count++;
            }
        }
        avgTemp = count == 0 ? 0 : temp / count;

        //6月下旬降雨量
        double rain6 = 0.0;
        String time3 = year + "-06-21 00:00:00";
        String time4 = year + "-06-30 23:00:00";

        MsgMediumSmallScale msgMediumSmallScale = msgMediumSmallScaleService.selectSumRainByParam(time3, time4, stationId);
        if (msgMediumSmallScale != null && msgMediumSmallScale.getRain() != null) {
            rain6 = msgMediumSmallScale.getRain();
        }

        //8月中旬降雨量
        double rain8 = 0.0;
        String time5 = year + "-08-11 00:00:00";
        String time6 = year + "-08-20 23:00:00";

        MsgMediumSmallScale msgMediumSmallScale1 = msgMediumSmallScaleService.selectSumRainByParam(time5, time6, stationId);
        if (msgMediumSmallScale1 != null && msgMediumSmallScale1.getRain() != null) {
            rain8 = msgMediumSmallScale1.getRain();
        }


        //9月上旬降雨日数
        int rainNumber9 = 0;
        for (int i = 1; i <= 10; i++) {
            String time7 = year + "-09-" + i + " 00:00:00";
            String time8 = year + "-09-" + i + " 23:00:00";
            MsgMediumSmallScale msgMediumSmallScale2 = msgMediumSmallScaleService.selectSumRainByParam(time7, time8, stationId);
            if (msgMediumSmallScale2 != null && msgMediumSmallScale2.getRain() != null && msgMediumSmallScale2.getRain() > 0) {
                rainNumber9++;
            }
        }

        //气象产量
        double qxCl = 0.0;
        qxCl = 5.8220 * avgTemp - 0.1423 * rain6 + 0.2868 * rain8 + 4.446 * rainNumber9;

        //趋势产量
        double qsCl = 0.0;
        long yearNumber1 = year - 1;
        long yearNumber2 = year - 2;
        long yearNumber3 = year - 3;

        List<Double> yields1 = cropyieldHistoryService.listYieldByParam(yearNumber1, stationId, type, "双季晚稻");
        List<Double> yields2 = cropyieldHistoryService.listYieldByParam(yearNumber2, stationId, type, "双季晚稻");
        List<Double> yields3 = cropyieldHistoryService.listYieldByParam(yearNumber3, stationId, type, "双季晚稻");

        if (yields1.size() > 0 && yields2.size() > 0 && yields3.size() > 0) {
            qsCl = (yields1.get(0) + yields2.get(0) + yields3.get(0) / 2);
        }

        //随机产量
        double sjCl = 0.0;
        String s;
        double q;
        String m;
        double yq;
        List<AgriWeatherDistRecord> agriWeatherDistRecords = agriWeatherDistRecordService.getList1("双季晚稻", stationId, year);

        for (AgriWeatherDistRecord agriWeatherDistRecord : agriWeatherDistRecords) {
            s = agriWeatherDistRecord.getAffectarea();
            m = agriWeatherDistRecord.getCroparea();
            if (!m.equals("0") && !m.equals("")) {
                q = Double.parseDouble(s) / Double.parseDouble(m);
                yq = (Double.parseDouble(s) * q * (qsCl + qxCl)) / Double.parseDouble(m);
                sjCl = sjCl + yq;
            } else {
                sjCl = 0.0;
            }
        }
        return new NyClDto(qxCl, qsCl, sjCl);
    }

    @Override
    public double ybzz(double qxCl, double qsCl, double sjCl, String cropName, String stationId, long year, String type) {
        double yield = qxCl + qsCl + sjCl;
        List<String> yields;
        if (StringUtils.isNotBlank(type)) {
            yields = cropyieldFcstService.getYield(stationId, year, cropName, type);
        } else {
            yields = cropyieldFcstService.getYield1(stationId, year, cropName);
        }

        CropyieldFcst cropyieldFcst = new CropyieldFcst();
        cropyieldFcst.setYear((int) year);
        cropyieldFcst.setType(type);
        cropyieldFcst.setYield(yield);
        cropyieldFcst.setCropname(cropName);
        cropyieldFcst.setStationid(stationId);
        if (yields.size() > 0) {
            cropyieldFcstService.update(cropyieldFcst);
        } else {
            cropyieldFcstService.save(cropyieldFcst);
        }
        return yield;
    }

    @Override
    public List<CropYieldFcstListVo> listYieldFcstVo(long year1, long year2, String stationId, String type, String cropName) {
        List<CropyieldFcst> cropyieldFcsts = cropyieldFcstService.getList4(year1, year2, stationId, type, cropName);
        List<CropYieldFcstListVo> list = new ArrayList<>();
        for (CropyieldFcst cropyieldFcst : cropyieldFcsts) {
            CropYieldFcstListVo cropYieldFcstListVo = new CropYieldFcstListVo();
            cropYieldFcstListVo.setYear(cropyieldFcst.getYear());
            cropYieldFcstListVo.setYield(cropyieldFcst.getYield());
            list.add(cropYieldFcstListVo);
        }
        return list;
    }

    @Override
    public List<CropYieldHistoryListVo> listYieldHistoryVo(long year1, long year2, String stationId, String type, String cropName) {
        List<CropyieldHistory> cropyieldHistories = cropyieldHistoryService.listByParams(stationId, cropName, type, year1, year2);
        List<CropYieldHistoryListVo> list = new ArrayList<>();
        for (CropyieldHistory cropyieldHistory : cropyieldHistories) {
            CropYieldHistoryListVo cropYieldHistoryListVo = new CropYieldHistoryListVo();
            cropYieldHistoryListVo.setYear(cropyieldHistory.getYear());
            cropYieldHistoryListVo.setYield(cropyieldHistory.getYield());
            list.add(cropYieldHistoryListVo);
        }
        return list;
    }

    @Override
    public Object generateDocument(String stationName, Timestamp forecastTime, Timestamp makeTime, String maker, String type, String breed, Integer YW, Integer YT, Integer YQ) {
        LocalDate currentDate = LocalDate.now();
        int year = currentDate.getYear();
        int month = currentDate.getMonthValue();
        int day = currentDate.getDayOfMonth();

        if (type.contains("晚稻")) {
            //晚稻预报

            //生成的word的名称，也是productName
            String docName = year + "-" + month + "-" + day + "晚稻产量预报.docx";
            String productName = docName;
            String productType = "晚稻产量预报";

            //判断pg数据库中是否存在该数据
            Integer id = agriProductService.queryId(productName, productType, forecastTime, makeTime, maker);
            if (id != null) {
                //存在，根据id查找mongo数据库
                HyDocFile byId = docFileService.getById(String.valueOf(id));
                //判断是否存在
                if (byId != null) {
                    //存在则直接返回
                    return byId.getData();
                } else {
                    //mongo数据库中不存在,将数据保存金mongo,并返回byte[]流
                    return docxToMongoDb(String.valueOf(id), docName, stationName, breed, year, month, day, YW, YT, YQ);
                }
            } else {
                //pg数据库中没有,新建存入
                AgriProduct agriProduct = new AgriProduct();
                //文档名称 : 2023-07-06晚稻产量预报.docx
                agriProduct.setProductname(docName);
                //产品类型
                agriProduct.setProducttype(productType);
                //预报时间
                agriProduct.setForecasttime(forecastTime);
                //制作时间
                agriProduct.setMaketime(makeTime);
                //制作人
                agriProduct.setMaker(maker);
                //状态
                agriProduct.setState("0");
                int insert = agriProductMapper.insert(agriProduct);
                if (insert > 0) {
                    Integer id1 = agriProductMapper.selectId(productName, productType, forecastTime, makeTime, maker);
                    return docxToMongoDb(String.valueOf(id1), docName, stationName, breed, year, month, day, YW, YT, YQ);
                } else {
                    return "保存数据失败";
                }

            }
        } else if (type.contains("早稻")) {
            //早稻预报

            //生成的word的名称，也是productName
            String docName = year + "-" + month + "-" + day + "早稻产量预报.docx";
            String productName = docName;
            String productType = "早稻产量预报";

            //判断pg数据库中是否存在该数据
            Integer id = agriProductService.queryId(productName, productType, forecastTime, makeTime, maker);
            if (id != null) {
                //存在，根据id查找mongo数据库
                HyDocFile byId = docFileService.getById(String.valueOf(id));
                //判断是否存在
                if (byId != null) {
                    //存在则直接返回
                    return byId.getData();
                } else {
                    //mongo数据库中不存在,将数据保存金mongo,并返回byte[]流
                    return docxToMongoDb(String.valueOf(id), docName, stationName, breed, year, month, day, YW, YT, YQ);
                }
            } else {
                //pg数据库中没有,新建存入
                AgriProduct agriProduct = new AgriProduct();
                //文档名称 : 2023-07-06晚稻产量预报.docx
                agriProduct.setProductname(docName);
                //产品类型
                agriProduct.setProducttype(productType);
                //预报时间
                agriProduct.setForecasttime(forecastTime);
                //制作时间
                agriProduct.setMaketime(makeTime);
                //制作人
                agriProduct.setMaker(maker);
                //状态
                agriProduct.setState("0");
                int insert = agriProductMapper.insert(agriProduct);
                if (insert > 0) {
                    Integer id1 = agriProductMapper.selectId(productName, productType, forecastTime, makeTime, maker);
                    return docxToMongoDb(String.valueOf(id1), docName, stationName, breed, year, month, day, YW, YT, YQ);
                } else {
                    return "保存数据失败";
                }
            }
        }
        return "只能生成早稻和晚稻的预报";
    }

    @Override
    public NyClDto earlycalculate(long year, String stationId, String type, String sunhour) {
        double temp = 0.0;//9月中旬的积温
        double avgTemp = 0.0;//9月中旬平均温度
        //区域自动站站点ID
        String smallScaleStationId;
        StationInfo nyStation = stationInfoService.getById(stationId);
        smallScaleStationId = nyStation.getSmallscalestationid();

        //5月降水量
        double rain = 0.0;
        String time3 = year + "-05-01 00:00:00";
        String time4 = year + "-05-01 23:00:00";

        MsgMediumSmallScale msglist = msgMediumSmallScaleService.selectSumRainByParam(time3, time4, stationId);
        if (msglist != null && msglist.getRain() != null) {
            rain = msglist.getRain();
        }

        //5月日平均温度<20度的日数
        int count = 0;
        for (int i = 1; i <= 31; i++) {
            String time1 = year + "-05-" + i + " 00:00:00";
            String time2 = year + "-05-" + i + " 23:00:00";

            MsgMediumSmallScale msgMediumSmallScale = msgMediumSmallScaleService.selectMaxMinTempByParam(time1, time2, smallScaleStationId);
            if (msgMediumSmallScale != null && msgMediumSmallScale.getMaxtemp() != null && msgMediumSmallScale.getMintemp() != null) {
                if ((msgMediumSmallScale.getMaxtemp() + msgMediumSmallScale.getMintemp()) / 2 < 20)
                    count++;
            }
        }
        int num = count;//5月日平均温度<20度的日数

        //5月中旬日照时数
        String rzs = sunhour;

        //5月1日-5月25日大于17度的有效积温
        double YXJWnum = 0;
        for (int i = 1; i <= 25; i++) {
            String time7 = year + "-05-" + i + " 00:00:00";
            String time8 = year + "-05-" + i + " 23:00:00";
            MsgMediumSmallScale msgMediumSmallScale2 = msgMediumSmallScaleService.selectSumRainByParam(time7, time8, stationId);
            if (msgMediumSmallScale2 != null && msgMediumSmallScale2.getRain() != null && msgMediumSmallScale2.getRain() > 0) {
                if ((msgMediumSmallScale2.getMaxtemp() + msgMediumSmallScale2.getMintemp()) / 2 > 17.0)
                    YXJWnum++;
            }
        }

        //气象产量
        double qxCl = 0.0;
        qxCl = -0.0976 * rain + 0.5751 * Double.parseDouble(rzs) - 4.7080 * num - 0.0002 * YXJWnum;

        //趋势产量
        double qsCl = 0.0;
        long yearNumber1 = year - 1;
        long yearNumber2 = year - 2;
        long yearNumber3 = year - 3;

        List<Double> yields1 = cropyieldHistoryService.listYieldByParam(yearNumber1, stationId, type, "双季早稻");
        List<Double> yields2 = cropyieldHistoryService.listYieldByParam(yearNumber2, stationId, type, "双季早稻");
        List<Double> yields3 = cropyieldHistoryService.listYieldByParam(yearNumber3, stationId, type, "双季早稻");

        if (yields1.size() > 0 && yields2.size() > 0 && yields3.size() > 0) {
            qsCl = (yields1.get(0) + yields2.get(0) + yields3.get(0) / 2);
        }

        //随机产量
        double sjCl = 0.0;
        String s;
        double q;
        String m;
        double yq;
        List<AgriWeatherDistRecord> agriWeatherDistRecords = agriWeatherDistRecordService.getList1("双季早稻", stationId, year);

        for (AgriWeatherDistRecord agriWeatherDistRecord : agriWeatherDistRecords) {
            s = agriWeatherDistRecord.getAffectarea();
            m = agriWeatherDistRecord.getCroparea();
            if (!m.equals("0") && !m.equals("")) {
                q = Double.parseDouble(s) / Double.parseDouble(m);
                yq = (Double.parseDouble(s) * q * (qsCl + qxCl)) / Double.parseDouble(m);
                sjCl = sjCl + yq;
            } else {
                sjCl = 0.0;
            }
        }
        return new NyClDto(qxCl, qsCl, sjCl);
    }

    @Override
    public List<CropYieldFcstListVo> listYieldFcst(String year, String cropName, String type) {
        List<CropyieldFcst> cropyieldFcsts = cropyieldFcstService.getList(Integer.parseInt(year), cropName, type);
        List<CropYieldFcstListVo> list = new ArrayList<>();
        for (CropyieldFcst cropyieldFcst : cropyieldFcsts) {
            CropYieldFcstListVo cropYieldFcstListVo = new CropYieldFcstListVo();
            cropYieldFcstListVo.setStationid(cropyieldFcst.getStationid());
            cropYieldFcstListVo.setYield(cropyieldFcst.getYield());
            list.add(cropYieldFcstListVo);
        }
        return list;
    }

    public ResponseEntity<byte[]> docxToMongoDb(String id, String docName, String stationName, String breed, int year, int month, int day, Integer YW, Integer YT, Integer YQ) {
        ResponseEntity<byte[]> responseEntity = toDocx(docName, stationName, breed, year, month, day, YW, YT, YQ);
        if (responseEntity.getStatusCode() == HttpStatus.OK) {
            byte[] byteArray = responseEntity.getBody();
            // 保存进mongo
            HyDocFile hyDocFile = new HyDocFile();
            hyDocFile.setData(byteArray);
            hyDocFile.setId(String.valueOf(id));
            hyDocFile.setTable_name("agri_product");
            hyDocFile.setName(docName);
            docFileService.save(hyDocFile);
            return responseEntity;
        } else {
            // 处理请求不成功的情况
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }

    public ResponseEntity<byte[]> toDocx(String docName, String stationName, String breed, int year, int month, int day, Integer YW, Integer YT, Integer YQ) {
        // 模板文件路径
        String templateFilePath = "templates/yieldForecastTemp/晚稻产量预报.docx";
        String outputFilePath = docFilePath + "/" + docName;

        //模板中需要更换的字段
        String[] placeholders = new String[]{"[7]", "[9]", "[8]", "[1]", "[2]", "[3]", "[0]", "[4]", "[5]", "[6]"};
        String[] replacements = new String[]{stationName, breed, String.valueOf(year), String.valueOf(year), String.valueOf(month), String.valueOf(day), String.valueOf(YT + YW + YQ), String.valueOf(YT), String.valueOf(YW), String.valueOf(YQ)};

        try (XWPFDocument document = new XWPFDocument(new ClassPathResource(templateFilePath).getInputStream());
             FileOutputStream outputStream = new FileOutputStream(outputFilePath);
             FileInputStream inputStream = new FileInputStream(outputFilePath);
             ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()
        ) {
            for (XWPFParagraph paragraph : document.getParagraphs()) {
                replaceTextInParagraphWithSubscript(paragraph, placeholders, replacements);
            }

            // 将生成的文档保存到输出文件
            document.write(outputStream);

            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                byteArrayOutputStream.write(buffer, 0, bytesRead);
            }

            byte[] byteArray = byteArrayOutputStream.toByteArray();

            HttpHeaders headers = new HttpHeaders();
            headers.setContentDispositionFormData("attachment", docName);
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            headers.setContentLength(byteArray.length);

            return new ResponseEntity<>(byteArray, headers, HttpStatus.OK);

        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


}
